package com.open.basic.job;

import com.open.basic.exception.BizException;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;


/**
 * @author: system
 * @Date: 2024/10/17 下午4:21
 * @Version: V1.0
 * @description: | Spring定时任务(单机版，分布式不建议使用，如需使用，请获取分布式锁)
 */

public class BasicTask {

    /**
     * 状态名称
     */
    private static final List<String> STATUS_LIST_NAME = List.of("未开始", "执行中", "执行成功", "执行失败");

    /**
     * 状态ID
     */
    private static final List<String> STATUS_LIST = List.of("wait", "running", "success", "fail");

    /**
     * 未执行
     */
    public static final String STATUS_WAIT = "wait";

    /**
     * 执行中
     */
    public static final String STATUS_RUNNING = "running";

    /**
     * 执行成功
     */
    public static final String STATUS_SUCCESS = "success";

    /**
     * 执行失败
     */
    public static final String STATUS_FAIL = "fail";

    /**
     * 任务ID
     */
    private String taskId;

    /**
     * 任务名称
     */
    private String taskName;

    /**
     * 任务描述
     */
    private String taskDesc;

    /**
     * 任务参数
     */
    private String param;

    /**
     * cron表达式
     */
    private String cron;

    /**
     * 任务执行类  继承该抽象类，重写execute方法
     */
    private String taskClass;

    /**
     * 任务执行次数
     */
    private int executeCount;
    /**
     * 状态 wait 未开始 running 执行中 success 执行成功  fail 执行失败
     */
    private String status;

    /**
     * 失败原因
     */
    private String failureMessage;

    /**
     * 执行开始时间
     */
    private LocalDateTime executionStartTime;
    /**
     * 执行结束时间
     */
    private LocalDateTime executionEndTime;

    /**
     * 执行耗时 单位秒
     */
    private long taskDuration;

    /**
     * 任务第一次执行时间
     */
    private LocalDateTime firstRunTime;

    /**
     * 任务最后执行时间
     */
    private LocalDateTime lastRunTime;
    /**
     * 下次执行时间
     */
    private LocalDateTime nextExecutionTime;


    private BasicTask(final String taskId, final String taskName, final String taskDesc, final String param, final String cron, final String taskClass, final String status) {
        this.taskId = taskId;
        this.taskName = taskName;
        this.taskDesc = taskDesc;
        this.param = param;
        this.cron = cron;
        this.taskClass = taskClass;
        this.status = status;
    }

    // 静态方法，用于生成一个 Builder，这个不一定要有，不过写这个方法是一个很好的习惯，
    // 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
    public static BasicTaskBuilder build() {
        return new BasicTaskBuilder();
    }


    public static class BasicTaskBuilder {

        /**
         * 任务ID
         */
        private String taskId;

        /**
         * 任务名称
         */
        private String taskName;

        /**
         * 任务描述
         */
        private String taskDesc;

        /**
         * 任务参数
         */
        private String param;

        /**
         * cron表达式
         */
        private String cron;

        /**
         * 任务执行类  继承该抽象类，重写execute方法
         */
        private String taskClass;
        /**
         * 状态 未开始 执行中 执行完成 执行失败
         */
        private String status;

        private BasicTaskBuilder() {
        }

        public BasicTaskBuilder setTaskId(final String taskId) {
            this.taskId = taskId;
            return this;
        }

        public BasicTaskBuilder setTaskName(final String taskName) {
            this.taskName = taskName;
            return this;
        }

        public BasicTaskBuilder setTaskDesc(final String taskDesc) {
            this.taskDesc = taskDesc;
            return this;
        }

        public BasicTaskBuilder setParam(final String param) {
            this.param = param;
            return this;
        }

        public BasicTaskBuilder setCron(final String cron) {
            this.cron = cron;
            return this;
        }

        public BasicTaskBuilder setTaskClass(final String taskClass) {
            this.taskClass = taskClass;
            return this;
        }

        public BasicTaskBuilder setStatus(final String status) {
            this.status = status;
            return this;
        }

        // build() 方法负责将 BasicTaskBuilder 中设置好的属性“复制”到 User 中。
        // 当然，可以在 “复制” 之前做点检验
        public BasicTask build() {
            if (!StringUtils.hasText(taskId)) {
                throw new BizException("任务ID不能为空");
            }
            if (!StringUtils.hasText(taskName)) {
                throw new BizException("任务名称不能为空");
            }
            if (!StringUtils.hasText(cron)) {
                throw new BizException("cron表达式不能为空");
            }
            // if (taskClass == null) {
            //     throw new BizException("任务执行类不能为空");
            // }
            if (!StringUtils.hasText(status)) {
                throw new BizException("任务状态不能为空");
            }
            if (!STATUS_LIST.contains(status)) {
                throw new BizException("任务状态不合法");
            }
            if (!CronExpression.isValidExpression(cron)) {
                throw new BizException("[" + cron + "]cron表达式不合法");
            }
            return new BasicTask(taskId, taskName, taskDesc, param, cron, taskClass, status);
        }
    }

    public String getTaskId() {
        return taskId;
    }

    public BasicTask setTaskId(final String taskId) {
        this.taskId = taskId;
        return this;
    }

    public String getTaskName() {
        return taskName;
    }

    public BasicTask setTaskName(final String taskName) {
        this.taskName = taskName;
        return this;
    }

    public String getTaskDesc() {
        return taskDesc;
    }

    public BasicTask setTaskDesc(final String taskDesc) {
        this.taskDesc = taskDesc;
        return this;
    }

    public String getParam() {
        return param;
    }

    public BasicTask setParam(final String param) {
        this.param = param;
        return this;
    }

    public String getCron() {
        return cron;
    }

    public BasicTask setCron(final String cron) {
        Objects.requireNonNull(cron);
        if (!CronExpression.isValidExpression(cron)) {
            throw new BizException("cron表达式不合法");
        }
        this.cron = cron;
        return this;
    }

    public String getTaskClass() {
        return taskClass;
    }

    public BasicTask setTaskClass(final String taskClass) {
        this.taskClass = taskClass;
        return this;
    }

    public String getStatus() {
        return status;
    }

    public BasicTask setStatus(final String status) {
        this.status = status;
        return this;
    }

    public String getFailureMessage() {
        return failureMessage;
    }

    public BasicTask setFailureMessage(final String failureMessage) {
        this.failureMessage = failureMessage;
        return this;
    }

    public LocalDateTime getExecutionStartTime() {
        return executionStartTime;
    }

    public BasicTask setExecutionStartTime(final LocalDateTime executionStartTime) {
        this.executionStartTime = executionStartTime;
        return this;
    }

    public LocalDateTime getExecutionEndTime() {
        return executionEndTime;
    }

    public BasicTask setExecutionEndTime(final LocalDateTime executionEndTime) {
        this.executionEndTime = executionEndTime;
        return this;
    }

    public long getTaskDuration() {
        return taskDuration;
    }

    public BasicTask setTaskDuration(final long taskDuration) {
        this.taskDuration = taskDuration;
        return this;
    }

    public LocalDateTime getNextExecutionTime() {
        return nextExecutionTime;
    }

    public BasicTask setNextExecutionTime(final LocalDateTime nextExecutionTime) {
        this.nextExecutionTime = nextExecutionTime;
        return this;
    }

    public int getExecuteCount() {
        return executeCount;
    }

    public BasicTask setExecuteCount(final int executeCount) {
        this.executeCount = executeCount;
        return this;
    }

    public LocalDateTime getFirstRunTime() {
        return firstRunTime;
    }

    public BasicTask setFirstRunTime(final LocalDateTime firstRunTime) {
        this.firstRunTime = firstRunTime;
        return this;
    }

    public LocalDateTime getLastRunTime() {
        return lastRunTime;
    }

    public BasicTask setLastRunTime(final LocalDateTime lastRunTime) {
        this.lastRunTime = lastRunTime;
        return this;
    }
}
